package com.gw.base;

import com.jfinal.kit.JsonKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by wangrenhui on 2014/7/1.
 */
@SuppressWarnings({ "serial", "rawtypes" })
public abstract class BaseModel<M extends BaseModel> extends Model<M> {

  private Table table;
  private String tableName;
  private String[] primaryKey;
  private String modelName;

  private String selectSql;
  private String fromSql;
  private String updateSql;
  private String deleteSql;
  private String dropSql;
  private String countSql;

  protected static String blank = " ";

  public Map<String, Object> getAttrs() {
    return super.getAttrs();
  }

  /**
   * 获取json字符串
   * @return
   */
  public String getJson() {
    return JsonKit.toJson(this);
  }

  /**
   * 查询全部数据
   * @return
   */
  public List<M> findAll() {
    return find(getSelectSql() + getFromSql());
  }

  /**
   * 根据where条件查询全部数据 如：List<User> users = User.dao.findBy(" `user`.deleted_at is null", loginName); `user` 数据库的别名 `modelName首字母小写`  `符号避免关键字
   * @param where
   * @param paras
   * @return
   */
  public List<M> findBy(String where, Object... paras) {
    return find(getSelectSql() + getFromSql() + getWhere(where), paras);
  }

  /**
   * 查询前几条
   * @param topNumber
   * @param where
   * @param paras
   * @return
   */
  public List<M> findTopBy(int topNumber, String where, Object... paras) {
    return paginate(1, topNumber, getSelectSql(), getFromSql() + getWhere(where), paras).getList();
  }

  /**
   * 查询第一个
   * @param where
   * @param paras
   * @return
   */
  public M findFirstBy(String where, Object... paras) {
    return findFirst(getSelectSql() + getFromSql() + getWhere(where), paras);
  }

  /**
   * 分页查询所有数据
   * @param pageNumber
   * @param pageSize
   * @return
   */
  public Page<M> paginateAll(int pageNumber, int pageSize) {
    return paginate(pageNumber, pageSize, getSelectSql(), getFromSql());
  }

  /**
   * 根据where条件分页
   * @param pageNumber
   * @param pageSize
   * @param where
   * @param paras
   * @return
   */
  public Page<M> paginateBy(int pageNumber, int pageSize, String where, Object... paras) {
    return paginate(pageNumber, pageSize, getSelectSql(), getFromSql() + getWhere(where), paras);
  }

  /**
   * 更新所有数据 set格式不支持前缀直接列名1=value，列名2=value...
   * @param set
   * @param paras
   * @return
   */
  public boolean updateAll(String set, Object... paras) {
    return Db.update(getUpdateSql() + getSet(set), paras) > 0;
  }

  /**
   * 通过条件更新
   * @param set
   * @param where
   * @param paras
   * @return
   */
  public boolean updateBy(String set, String where, Object... paras) {
    return Db.update(getUpdateSql() + getSet(set) + getWhere(where), paras) > 0;
  }

  /**
   * 逻辑删除  需要表中存在一个  deleted_at Date类型  逻辑删除的时候存入时间  实际是update该值/数据安全
   * @return
   */
  public boolean deleteAll() {
    return Db.update(getDeleteSql(), new Date()) > 0;
  }

  /**
   * 根据条件逻辑删除
   * @param where
   * @param paras
   * @return
   */
  public boolean deleteBy(String where, Object... paras) {
    Object[] realParas = new Object[paras.length + 1];
    realParas[0] = new Date();
    for (int i = 0; i < paras.length; i++) {
      realParas[i + 1] = paras[i];
    }
    return Db.update(getDeleteSql() + getWhere(where), realParas) > 0;
  }

  /**
   * 物理删除 执行sql里的delete
   * @return
   */
  public boolean dropAll() {
    return Db.update(getDropSql()) > 0;
  }

  /**
   * 根据条件物理删除
   * @param where
   * @param paras
   * @return
   */
  public boolean dropBy(String where, Object... paras) {
    return Db.update(getDropSql() + getWhere(where), paras) > 0;
  }

  /**
   * count函数 计算总数量
   * @return
   */
  public Long countAll() {
    return Db.queryFirst(getCountSql());
  }

  /**
   * 根据条件计算数量
   * @param where
   * @param paras
   * @return
   */
  public Long countBy(String where, Object... paras) {
    return Db.queryFirst(getCountSql() + getWhere(where), paras);
  }
  
  
  
  protected String getSet(String set) {
    if (set != null && !set.isEmpty() && !set.trim().toUpperCase().startsWith("SET")) {
      set = " SET " + set;
    }
    return set;
  }

  protected String getWhere(String where) {
    if (where != null && !where.isEmpty() && !where.trim().toUpperCase().startsWith("WHERE")) {
      where = " WHERE " + where;
    }
    return where;
  }

  @SuppressWarnings("unchecked")
public Table getTable() {
    if (table == null) {
      Class clazz = getClass();
      table = TableMapping.me().getTable(clazz);
    }
    return table;
  }

  
  public String[] getPrimaryKey() {
    if (primaryKey == null) {
      primaryKey = getTable().getPrimaryKey();
    }
    return primaryKey;
  }

  public String getTableName() {
    if (tableName == null) {
      tableName = getTable().getName();
    }
    return tableName;
  }

  public String getModelName() {
    if (modelName == null) {
      Class clazz = getClass();
      byte[] items = clazz.getSimpleName().getBytes();
      items[0] = (byte) ((char) items[0] + ('a' - 'A'));
      modelName = new String(items);
    }
    return modelName;
  }

  public String getSelectSql() {
    if (selectSql == null) {
      selectSql = " SELECT `" + getModelName() + "`.* ";
    }
    return selectSql;
  }

  public String getFromSql() {
    if (fromSql == null) {
      fromSql = " FROM " + getTableName() + " `" + getModelName() + "` ";
    }
    return fromSql;
  }

  public String getUpdateSql() {
    if (updateSql == null) {
      updateSql = " UPDATE " + getTableName() + " `" + getModelName() + "` ";
    }
    return updateSql;
  }

  public String getDeleteSql() {
    if (deleteSql == null) {
      deleteSql = " UPDATE " + getTableName() + " `" + getModelName() + "` SET `" + getModelName() + "`.deleted_at=? ";
    }
    return deleteSql;
  }

  public String getDropSql() {
    if (dropSql == null) {
      dropSql = " DELETE FROM " + getTableName() + " ";
    }
    return dropSql;
  }

  public String getCountSql() {
    if (countSql == null) {
      countSql = " SELECT COUNT(*) count FROM " + getTableName() + " `" + getModelName() + "` ";
    }
    return countSql;
  }

  public String getNextSql(String where) {
    String nextSql = " WHERE `" + getModelName() + "`." + getPrimaryKey()
        + "=(SELECT MIN(`_" + getModelName() + "`." + getPrimaryKey() + ") FROM " + getTableName() + " `_" + getModelName() + "`" + getWhere(where) + ")";

    return nextSql;
  }

  public String getPreviousSql(String where) {
    String previousSql = " WHERE `" + getModelName() + "`." + getPrimaryKey()
        + "=(SELECT MAX(`_" + getModelName() + "`." + getPrimaryKey() + ") FROM " + getTableName() + " `_" + getModelName() + "`" + getWhere(where) + ")";
    return previousSql;
  }
}
